package vin.pth.authentication.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import pth.authentication.service.AuthenticationUserService;
import reactor.core.publisher.Mono;
import vin.pth.authentication.handler.AuthenticationHandler;
import vin.pth.base.pojo.DefaultUserDetails;
import vin.pth.base.service.UserDetailsService;

/**
 * 鉴权模块默认Bean配置， 其中继承了一些通常需要自定义实现的bean， 为了引入时0实现启动，实际业务中虚也手动复写.
 *
 * @author cocoon
 */
@Slf4j
@ConditionalOnProperty(name = "cocoon-security.authentication.enable", matchIfMissing = true)
@Configuration
public class AuthenticationDefaultBeanConfig {

  private static final String ADMIN_USERNAME = "admin";


  @ConditionalOnMissingBean(PasswordEncoder.class)
  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }


  /**
   * UserDetailsService的默认实现，默认实现.
   *
   * @return UserDetailsService
   */
  @ConditionalOnMissingBean
  @Bean
  public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
    return username -> {
      log.warn("默认的UserDetails，请自行实现！");
      if (username.equals(ADMIN_USERNAME)) {
        return DefaultUserDetails.adminUser(passwordEncoder.encode(ADMIN_USERNAME));
      }
      return DefaultUserDetails.anonymousUser();
    };
  }


  /**
   * AuthenticationUserService，默认实现.
   *
   * @return AuthenticationUserService
   */
  @ConditionalOnMissingBean
  @Bean
  public AuthenticationUserService authenticationUserService(PasswordEncoder passwordEncoder) {
    return token -> {
      if (token.equals(ADMIN_USERNAME)) {
        return DefaultUserDetails.adminUser(passwordEncoder.encode(ADMIN_USERNAME));
      }
      log.warn("默认的{}，默认返回匿名用户，请根据业务自行实现该接口！", "AuthenticationUserService");
      return DefaultUserDetails.anonymousUser();
    };
  }


  /**
   * 鉴权失败处理器.
   *
   * @return AuthenticationHandler
   */
  @ConditionalOnMissingBean
  @Bean
  public AuthenticationHandler authenticationHandler() {
    return (request, response, e) -> {
      log.warn("默认的鉴权失败处理,默认返回403");
      response.setStatusCode(HttpStatus.FORBIDDEN);
      response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
      Map<String, String> map = buildResp(e.getMessage());
      ObjectMapper objectMapper = new ObjectMapper();
      String resp;
      try {
        resp = objectMapper.writeValueAsString(map);
      } catch (JsonProcessingException ex) {
        throw new RuntimeException(ex);
      }
      return response.writeWith(
          Mono.just(response.bufferFactory().wrap(resp.getBytes())));
    };
  }

  private Map<String, String> buildResp(String message) {
    Map<String, String> map = new HashMap<>();
    map.put("message", message);
    return map;
  }


}
